package com.keqiang.chart.impl.radar.render

import android.graphics.Canvas
import android.graphics.Paint
import android.text.TextPaint
import com.keqiang.chart.impl.radar.XAxis
import com.keqiang.chart.impl.radar.impl.RadarChart
import com.keqiang.chart.utils.ObjectPool
import com.keqiang.chart.utils.to360Range
import com.keqiang.chart.utils.toRadian
import com.keqiang.utils.PaintUtils.getCenterBaseline
import com.keqiang.utils.PaintUtils.getChartHeight
import kotlin.math.cos
import kotlin.math.sin

/**
 * 雷达图X轴线绘制器
 *
 * @author Created by wanggaowan on 2022/10/27 13:06
 */
open class XAxisRender(val chart: RadarChart) : IAxisRender {

    override fun onDraw(canvas: Canvas, centerX: Float, centerY: Float, radius: Float, startAngle: Float) {
        var angle = startAngle
        val stepAngle = 360f / chart.xAxis.labelCount

        val paint = ObjectPool.obtainPaint<Paint>()
        val path = ObjectPool.obtainPath()

        paint.color = chart.xAxis.lineColor
        paint.strokeWidth = chart.xAxis.lineWidth
        paint.pathEffect = chart.xAxis.linePathEffect
        paint.style = Paint.Style.STROKE

        for (i in 0 until chart.xAxis.labelCount) {
            val radian = angle.toRadian
            val startY: Float
            val startX = if (chart.xAxis.lineStartOffset > 0) {
                startY = centerY + sin(radian) * chart.xAxis.lineStartOffset
                centerX + cos(radian) * chart.xAxis.lineStartOffset
            } else {
                startY = centerY
                centerX
            }

            val endX = centerX + cos(radian) * radius
            val endY: Float = centerY + sin(radian) * radius

            path.reset()
            path.moveTo(startX, startY)
            path.lineTo(endX, endY)
            canvas.drawPath(path, paint)

            drawLabel(canvas, i, angle, stepAngle, endX, endY, chart.xAxis)

            angle += stepAngle
        }

        ObjectPool.recyclePaint(paint)
        ObjectPool.recyclePath(path)
    }

    protected open fun drawLabel(canvas: Canvas, pos: Int, angle: Float, stepAngle: Float, endX: Float, endY: Float, xAxis: XAxis) {
        val text = xAxis.axisValueFormat?.invoke(pos) ?: return

        val textPaint = ObjectPool.obtainPaint<TextPaint>(true)
        textPaint.textSize = xAxis.labelTextSize
        textPaint.color = xAxis.labelColor

        val oneCharHeight = textPaint.getChartHeight()
        val oneCharHeightNoPadding = textPaint.getChartHeight(includePadding = false)
        val baseLine = textPaint.getCenterBaseline(includePadding = false)
        val mapAngle = angle.to360Range
        val radian = mapAngle.toRadian
        val x = endX + cos(radian) * xAxis.labelOffsetAxis
        val y = endY + sin(radian) * xAxis.labelOffsetAxis

        val minStepAngle = stepAngle.coerceAtMost(xAxis.angleErrorRange)
        if ((mapAngle > 90 - minStepAngle && mapAngle < 90 + minStepAngle)
            || (mapAngle > 270 - minStepAngle && mapAngle < 270 + minStepAngle)) {

            if (mapAngle < 180) {
                if (minStepAngle <= 0f || mapAngle == 90f) {
                    textPaint.textAlign = Paint.Align.CENTER
                    canvas.drawText(text, x, y + oneCharHeightNoPadding, textPaint)
                } else if (mapAngle > 90) {
                    textPaint.textAlign = Paint.Align.RIGHT
                    val textWidth = textPaint.measureText(text) / 2f
                    canvas.drawText(text, x + textWidth - (mapAngle - 90) / minStepAngle * textWidth,
                        y + oneCharHeightNoPadding, textPaint)
                } else {
                    val textWidth = textPaint.measureText(text) / 2f
                    canvas.drawText(text, x - textWidth + (90 - mapAngle) / minStepAngle * textWidth,
                        y + oneCharHeightNoPadding, textPaint)
                }
            } else if (minStepAngle <= 0f || mapAngle == 270f) {
                textPaint.textAlign = Paint.Align.CENTER
                canvas.drawText(text, x, y - (oneCharHeight - oneCharHeightNoPadding), textPaint)
            } else if (mapAngle < 270) {
                textPaint.textAlign = Paint.Align.RIGHT
                val textWidth = textPaint.measureText(text) / 2f
                canvas.drawText(text, x + textWidth - (270 - mapAngle) / minStepAngle * textWidth,
                    y - (oneCharHeight - oneCharHeightNoPadding), textPaint)
            } else {
                val textWidth = textPaint.measureText(text) / 2f
                canvas.drawText(text, x - textWidth + (mapAngle - 270) / minStepAngle * textWidth,
                    y - (oneCharHeight - oneCharHeightNoPadding), textPaint)
            }
        } else {
            if (mapAngle > 90 && mapAngle < 270) {
                textPaint.textAlign = Paint.Align.RIGHT
            }

            val offsetHeight = sin(angle.toRadian) * oneCharHeightNoPadding / 2f + baseLine
            canvas.drawText(text, x, y + offsetHeight, textPaint)
        }

        ObjectPool.recyclePaint(textPaint)
    }
}